package indi.zhifa.recipe.bailan.busy.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import indi.zhifa.recipe.bailan.busy.enums.EOrmEntityStatus;
import indi.zhifa.recipe.bailan.busy.service.IOrmJDBCService;
import indi.zhifa.recipe.bailan.busy.entity.po.OrmTestEntity;
import indi.zhifa.recipe.bailan.busy.entity.vo.PageData;
import lombok.RequiredArgsConstructor;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@RequiredArgsConstructor
@Service
public class OrmJDBCServiceImpl extends BaseOrmServiceImpl implements IOrmJDBCService {

    private final JdbcTemplate mJdbcTemplate;

    enum EParamType{
        EQ,
        LIKE,
        BIG,
        LESS,
        BETWEEN;
    }

    @Override
    public void initTestData() {
        List<OrmTestEntity> ormTestEntityList = getInitOrmTestEntityList("JDBC");
        String sql = "insert into c2_orm_test("+
                "id,app_code,app_name,module_code,module_name,code,name,status,description,value,"+
                "create_time,create_by,create_name,create_ip,modify_time,modify_by,modify_name,modify_ip,version,del) values(?,?,?,?,?,?,?,?,?,?," +
                "?,?,?,?,?,?,?,?,?,?)";
        List<Object[]> params = ormTestEntityList.stream().map(entity->entity.toParamList()).collect(Collectors.toList());
        mJdbcTemplate.batchUpdate(sql,params);
    }

    @Override
    public PageData<OrmTestEntity> page(int pCurrent, int pSize,
                                              String pAppCode, String pModuleCode, String pCode, String pName,
                                              EOrmEntityStatus pStatus, Integer pMin, Integer pMax) {
        StringBuilder sb = new StringBuilder();
        sb.append("select * from c2_orm_test");
        StringBuilder whereSb = new StringBuilder().append(" ");
        List<Object> params = new ArrayList<>();
        Boolean hasParam = false;
        addParam(whereSb,hasParam,params,"del",EParamType.EQ,0,null);
        addParam(whereSb,hasParam,params,"app_code",EParamType.EQ,pAppCode,null);
        addParam(whereSb,hasParam,params,"module_code",EParamType.EQ,pModuleCode,null);
        addParam(whereSb,hasParam,params,"code",EParamType.EQ,pCode,null);
        addParam(whereSb,hasParam,params,"name",EParamType.LIKE,pName,null);
        addParam(whereSb,hasParam,params,"status",EParamType.EQ,null !=pStatus ? pStatus.getCode(): null,null);
        if(null != pMin && null != pMax){
            addParam(whereSb,hasParam,params,"value",EParamType.BETWEEN,pMin,pMax);
        }else if(null != pMin){
            addParam(whereSb,hasParam,params,"value",EParamType.BIG,pMin,null);
        }else if(null != pMax){
            addParam(whereSb,hasParam,params,"value",EParamType.LESS,pMax,null);
        }
        sb.append(whereSb);
        PageData<OrmTestEntity> pageData = new PageData<OrmTestEntity>();
        pageData.setCurrent(pCurrent);
        pageData.setSize(pSize);
        String cntSql = String.format("select count(*) as cnt from (%s) as tmp", sb);
        Map<String,Object> cntRes = mJdbcTemplate.queryForMap(cntSql,params.toArray());
        int cnt = ((Long)cntRes.get("cnt")).intValue();
        if(cnt > 0){
            if(pSize > 0){
                sb.append(" LIMIT ").append((pCurrent-1) * pSize).append(", ").append(pSize);
            }
            List<Map<String, Object>> mapData = mJdbcTemplate.queryForList(sb.toString(),params.toArray());
            List<OrmTestEntity> data = mapData.stream().map(theMapData->
                    BeanUtil.mapToBean(theMapData,OrmTestEntity.class,true, CopyOptions.create())
            ).collect(Collectors.toList());
            pageData.setTotal(cnt);
            int pages = (int)Math.ceil((double)cnt/pSize);
            pageData.setPages(pages);
            pageData.setPageData(data);
        }else{
            pageData.setTotal(0);
            pageData.setPages(0);
        }

        return pageData;
    }

    private void addParam(StringBuilder pParamSb, Boolean pHasParam, List<Object> pParams, String pParamStr, EParamType pParamType, Object pParam1, Object pParam2){

        if(null != pParam1){
            if(pHasParam){
                pParamSb.append(" and ");
            }else{
                pParamSb.append("where ");
            }
            pHasParam = true;
            switch (pParamType){
                case EQ:
                    pParamSb.append(pParamStr + " = ?");
                    pParams.add(pParam1);
                    break;
                case LIKE:
                    pParamSb.append(pParamStr + " like ?");
                    pParams.add("%"+pParam1+"%");
                    break;
                case BIG:
                    pParamSb.append(pParamStr + " > ?");
                    pParams.add(pParam1);
                    break;
                case LESS:
                    pParamSb.append(pParamStr + " < ?");
                    pParams.add(pParam1);
                    break;
                case BETWEEN:
                    pParamSb.append(pParamStr + " between ? and ?");
                    pParams.add(pParam1);
                    pParams.add(pParam2);
                    break;
            }
        }
    }
}
